#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Tomahawk.Runtime.Screen.Controls;
using Tomahawk.Runtime.Screen.Animation;
#endregion

namespace Tomahawk.Runtime.Screen
{
    /// <summary>
    /// This is an utility class 
    /// </summary>
    public class ControlAnimator
    {

        public delegate void ControlAnimatorNotification();
        public event ControlAnimatorNotification OnAnimationFinished;

        List<ControlKeyFrame> keyFrames;
        float elapsedTime = 0;
        float totalTime = 0;
        float speed = 1;

        /// <summary>
        /// Constructor
        /// </summary>
        public ControlAnimator(float totalTime)
        {
            keyFrames = new List<ControlKeyFrame>();
            this.totalTime = totalTime;
        }

        /// <summary>
        /// Animate all the keyframes
        /// </summary>
        /// <param name="time"></param>
        public void Animate(float time)
        {
            //animate depending on the speed
            float tm = (time * this.speed);
            elapsedTime += tm;

            if (mustAnimate())
            {
                foreach (ControlKeyFrame kf in this.keyFrames)
                {
                    kf.Animate(tm, elapsedTime);
                }
            }
            else
            {
                //notify the client code this animation has ended
                if (OnAnimationFinished != null) OnAnimationFinished();
            }
        }

        /// <summary>
        /// Wheter the animation must go on, depending on the current elapsed time, and the speed
        /// </summary>
        private bool mustAnimate()
        {
            if (this.speed >= 0)
                return elapsedTime < totalTime;
            else
                return elapsedTime > 0;
        }

        /// <summary>
        /// Add a keyframe to the list of keyframes
        /// </summary>
        public void AddKeyFrame(ControlKeyFrame keyFrame)
        {
            this.keyFrames.Add(keyFrame);
        }

        #region "Factories"

        /// <summary>
        /// Add and animation on the alpha propertie
        /// </summary>
        public void AddAlphaKeyFrame(ScreenControl control, float startTime, float endTime, float startAlpha, float endAlpha)
        {
            AlphaKeyFrame akf = new AlphaKeyFrame(control, startTime, endTime);
            akf.StartAlpha = startAlpha;
            akf.EndAlpha = endAlpha;
            this.AddKeyFrame(akf);
        }

        /// <summary>
        /// Add an animation on the control's position
        /// </summary>
        public void AddPositionKeyFrame(ScreenControl control, float startTime, float endTime, int startX, int endX, int startY, int endY)
        {
            PositionKeyFrame pkf = new PositionKeyFrame(control, startTime, endTime);
            pkf.StartX = startX;
            pkf.StartY = startY;
            pkf.EndX = endX;
            pkf.EndY = endY;
            this.AddKeyFrame(pkf);
        }

        /// <summary>
        /// Add an animation on the size properties
        /// </summary>
        public void AddSizeKeyFrame(ScreenControl control, float startTime, float endTime, int startWidth, int endWidth, int startHeight, int endHeight)
        {
            SizeKeyFrame pkf = new SizeKeyFrame(control, startTime, endTime);
            pkf.StartWidth = startWidth;
            pkf.StartHeight = startHeight;
            pkf.EndWidth = endWidth;
            pkf.EndHeight = endHeight;
            this.AddKeyFrame(pkf);
        }

        #endregion

        /// <summary>
        /// Speed of the animation. Setting this to negative, the animation will run backwards
        /// </summary>
        public float Speed
        {
            get { return this.speed; }
            set
            {
                this.speed = value;
                this.Reset();
            }
        }

        /// <summary>
        /// Reset the animation to the starting point. 
        /// If the speed is negative, the elapsed point is set to total time
        /// </summary>
        public void Reset()
        {
            //reset the animator
            if (this.speed >= 0)
                this.elapsedTime = 0;
            else
                this.elapsedTime = this.totalTime;

            //reset all the keyframes
            foreach (ControlKeyFrame ckf in this.keyFrames)
                ckf.Reset(this.speed);
        }

    }

}


